#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 1e5+5, M = 1e6+6;
ll n, m, L, V;
struct node{
    ll l, r;
    ll id;
} car[N], carl[N], carr[N];
bool cmp1(node a, node b){
    return a.l < b.l;
}
bool cmp2(node a, node b){
    return a.r < b.r;
}
//ll has[M], pre[M];
ll det[N];
ll vis[N], finalvis[N];
ll x, y, z;
vector<int> tree, pretree;
int main(){
    freopen("detect.in", "r", stdin);
    freopen("detect.out", "w", stdout);
    int T;
    cin >> T;
    //T = 11;
    while(T--){
        //scanf("%lld %lld %lld %lld", &n, &m, &L, &V);
        cin >> n >> m >> L >> V;
        int cnt = 0;
        //printf("%lld %lld %lld %lld", n, m, L, V);
        for(int i = 1; i <= n; i++){
            scanf("%lld %lld %lld", &x, &y, &z);
            if(z == 0){
                if(y > V) car[++cnt] = {x, L, cnt};
            }
            else if(z < 0){
                if(y <= V) continue;
                else{
                    car[++cnt] = {x, min(L, x+(y*y-V*V-1)/(-2*z)), cnt};
                }
            }
            else{
                if(y > V) car[++cnt] = {x, L, cnt};
                else if(y == V) car[++cnt] = {x+1, L, cnt};
                else if(x+(V*V-y*y)/(2*z)+1 > L) continue;
                else{
                    car[++cnt] = {x+(V*V-y*y)/(2*z)+1, L, cnt};
                }
            }
        }
        sort(car+1, car+cnt+1, cmp1);
        for(int i = 1; i <= cnt; i++){
            carl[i] = car[i];
        }
        //for(int i = 1; i <= cnt; i++){
        //    printf("~~%lld %lld\n", car[i].l, car[i].r);
        //}
        sort(car+1, car+cnt+1, cmp2);
        for(int i = 1; i <= cnt; i++){
            carr[i] = car[i];
        }
        //memset(has, 0, sizeof(has));
        //memset(pre, 0, sizeof(pre));
        for(int i = 1; i <= m; i++){
            scanf("%lld", &det[i]);
        //    has[x] = 1;
        }
        sort(det+1, det+m+1);
        memset(vis, 0, sizeof(vis));
        memset(finalvis, 0, sizeof(finalvis));
        tree.clear();
        pretree.clear();
        //for(int i = 1; i <= L; i++){
        //    pre[i] = pre[i-1] + has[i];
        //}
        ll ans1 = 0, ans2 = 0;
        ll prel = 1, prer = 1;
        for(int i = 1; i <= m; i++){
            //for(auto v : pretree){
            //    printf("%lld ", v);
            //}
            //puts("");
            while(carl[prel].l <= det[i] && prel <= cnt){
                tree.insert(lower_bound(tree.begin(), tree.end(), carl[prel].id), carl[prel].id);
                if(carl[prel].r >= det[i]) vis[carl[prel].id] = 1;
                prel++;
            }
            while(carr[prer].r < det[i] && prer <= cnt){
                tree.erase(lower_bound(tree.begin(), tree.end(), carr[prer].id));
                if(!finalvis[carr[prer].id] && vis[carr[prer].id] == 1){
                    ans2++;
                    for(auto v : pretree){
                        finalvis[v] = 1;
                    }
                }
                prer++;
            }
            pretree = tree;
        }
        while(prel <= cnt){
            tree.insert(lower_bound(tree.begin(), tree.end(), carl[prel].id), carl[prel].id);
            prel++;
        }
        while(prer <= cnt){
            tree.erase(lower_bound(tree.begin(), tree.end(), carr[prer].id));
            if(!finalvis[carr[prer].id] && vis[carr[prer].id] == 1){
                ans2++;
                for(auto v : pretree){
                    finalvis[v] = 1;
                }
            }
            prer++;
        }
        for(int i = 1; i <= cnt; i++){
            if(vis[i]) ans1++;
        }
        printf("%lld %lld\n", ans1, m-ans2);
    }
    return 0;
}
